package com.runvp.service.biz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.runvp.common.config.DeviceConfig;
import com.runvp.common.config.RunvpConfig;
import com.runvp.common.constant.ConstantRedisKey;
import com.runvp.common.core.redis.RedisCache;
import com.runvp.common.core.text.Convert;
import com.runvp.common.enums.*;
import com.runvp.common.exception.base.BaseException;
import com.runvp.common.util.ToolUtils;
import com.runvp.common.utils.DateUtils;
import com.runvp.common.utils.http.HttpUtils;
import com.runvp.service.biz.domain.BizDevice;
import com.runvp.service.biz.domain.BizDeviceBO;
import com.runvp.service.biz.domain.BizDeviceCargo;
import com.runvp.service.biz.mapper.BizDeviceCargoMapper;
import com.runvp.service.biz.mapper.BizDeviceMapper;
import com.runvp.service.biz.service.IBizDeviceService;
import com.runvp.service.build.BuildQRCode;
import com.runvp.service.out.OutUtil;
import com.runvp.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设备Service业务层处理
 *
 * @author runvp
 * @date 2022-12-22
 */
@Slf4j
@Service
public class BizDeviceServiceImpl implements IBizDeviceService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private BizDeviceMapper bizDeviceMapper;
    @Autowired
    private BizDeviceCargoMapper bizDeviceCargoMapper;

    /**
     * 定时检测设备在线状态
     *
     * @param minutes
     */
    @Override
    public void checkDeviceOnline(Integer minutes) {
        BizDevice query = new BizDevice();
        List<BizDevice> devices = selectBizDeviceList(query);
        if (CollectionUtils.isEmpty(devices)) {
            log.warn("暂无设备");
            return;
        }
        JSONObject all = getDeviceStatus();
        String sn ;
        JSONObject checkDevice;
        for (BizDevice device : devices) {
            sn = device.getDeviceCode();
            try {
                long tm = System.currentTimeMillis() - device.getLastUpdateTime().getTime();
                //是否在有效期内
                boolean isOnline = false;
                boolean expireTime = true;
                //当前时间减去最后一次更新时间大于设置的有效时间则判定为离线
                if(tm > minutes*1000*60){
                    expireTime = false;
                }
                log.info("设备【{}】expireTime:{}",device.getDeviceCode(), expireTime);
                if(DeviceType.WECHAT.getCode().equals(device.getDeviceType())){
                    checkDevice = all.getJSONObject(sn);
                    if(null != checkDevice) {
                        isOnline = checkDevice.getBoolean("active") && expireTime;
                    }
                }else {
                    isOnline = expireTime;
                }
                if(isOnline){
                    if(LineStatus.ON_LINE.getCode().equals(device.getLineStatus())){
                        continue;
                    }
                    log.info("设备【{}】状态更新为:【{}】", sn, LineStatus.ON_LINE.getCode());
                    device.setUpdateTime(new Date());
                    device.setLineStatus(LineStatus.ON_LINE.getCode());
                    device.setUpdateBy("系统检测");
                    device.setRemark("系统检测设备在线");
                    updateBizDevice(device);
                    continue;
                }
                log.info("设备【{}】已离线,状态更新为:【{}】", sn, LineStatus.OFF_LINE.getCode());
                device.setUpdateTime(new Date());
                device.setLineStatus(LineStatus.OFF_LINE.getCode());
                device.setUpdateBy("系统检测");
                device.setRemark("系统检测设备掉线");
                updateBizDevice(device);
            } catch (Exception e) {
                log.error("本次处理设备【{}】在线状态异常:{}", sn, e);
            }
        }
    }

    /**
     * 获取所有设备在线情况
     *
     * @return boolean
     */
    private JSONObject getDeviceStatus() {
        try{
            String checkDeviceUrl = DeviceConfig.getCheckUrl();
            if(StringUtils.isBlank(checkDeviceUrl)){
                log.error("未配置检测设备在线地址,停止检测");
                return new JSONObject();
            }
//            String url = HutoolHttpClient.get(checkDeviceUrl);
            String url = HttpUtils.sendGet(checkDeviceUrl);
            log.info("设备在线情况:{}", url);
            JSONObject all = JSONObject.parseObject(url).getJSONObject("data").getJSONObject("all");
            return all;
        }catch (Exception e){
            log.error("获取所有设备在线情况异常:{}",e.getMessage());
            return new JSONObject();
        }
    }
    /**
     * 查询设备
     *
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public BizDevice selectBizDeviceById(Long id) {
        return bizDeviceMapper.selectBizDeviceById(id);
    }
    /**
     * 设备重启
     *
     * @param ids 设备重启dis
     * @return 结果
     */
    @Override
    public int restart(String ids) {
        log.info("本次执行【重启】指令ids:{}",ids);
        String[] arr = Convert.toStrArray(ids);
        int num = 0;
        for (String id : arr) {
            BizDevice bizDevice = selectBizDeviceById(ToolUtils.objTOLong(id));
            if (null == bizDevice) {
                continue;
            }
            //构建重启指令
            JSONObject param = new JSONObject();
            param.put("id",id);
            boolean res = OutUtil.restart(bizDevice.getDeviceCode(),param.toJSONString());
            log.info("本次执行【重启】指令结果:{}", res);
            if (res) {
                num++;
            }
        }
        return num;
    }

    /**
     * 查询设备列表
     *
     * @param bizDevice 设备
     * @return 设备
     */
    @Override
    public List<BizDevice> selectBizDeviceList(BizDevice bizDevice) {
        return bizDeviceMapper.selectBizDeviceList(bizDevice);
    }

    /**
     * 新增设备
     *
     * @param bizDevice 设备
     * @return 结果
     */
    @Override
    public int insertBizDevice(BizDevice bizDevice) {
        bizDevice.setDeviceType(DeviceType.BIG_SCREEN.getDesc());
        bizDevice.setCreateTime(DateUtils.getNowDate());
        bizDevice.setQrCode(BuildQRCode.createCode(bizDevice.getDeviceCode(), RunvpConfig.getPreview() + "/wechat.html?baseSn=" + bizDevice.getDeviceCode()));
        return bizDeviceMapper.insertBizDevice(bizDevice);
    }
    private boolean buildIeRefresh(String sn){
        String refreshKey = ConstantRedisKey.PRODUCT_REFRESH+sn;
        String refreshKeyFlag = redisCache.getCacheObject(refreshKey);
        if(StringUtils.isNotBlank(refreshKeyFlag) && YesOrNo.YES.getCode().equals(refreshKeyFlag)) {
            redisCache.deleteObject(refreshKey);
            return true;
        }
        return false;
    }
    /**
     * 设备心跳
     *
     * @param body 设备心跳
     * @return 结果
     */
    public Map<String,Object> xl(String sn, String body){
        Map<String,Object> map = new HashMap<>();
        map.put("status",1);
        map.put("isRefresh",false);
        if(StringUtils.isBlank(sn)){
            log.error("设备SN为空，停止执行");
            map.put("status",0);
            return map;
        }
        map.put("isRefresh",buildIeRefresh(sn));
        String deviceXlKey = ConstantRedisKey.DEVICE_XL+sn;
        long count = ToolUtils.objTOLong(redisCache.incr(deviceXlKey,1));
        //获取平台默认app设备心跳间隔次数
        long deviceXlIntervalRecordCount = ToolUtils.objTOLong(configService.selectConfigByKey("deviceXlIntervalRecordCount"));
        if(count > deviceXlIntervalRecordCount){
            //超过轮回次数,执行记录
            BizDevice device = new BizDevice();
            device.setDeviceCode(sn);
            device.setReserve(body);
            redisCache.deleteObject(deviceXlKey);
            map.put("status",deviceXL(device));
        }
        return map;
    }
    /**
     * 设备心跳
     *
     * @param bizDevice 设备心跳
     * @return 结果
     */
    public int deviceXL(BizDevice bizDevice) {
        //根据设备号查询是否存在
        String sn = bizDevice.getDeviceCode();
        BizDevice device = bizDeviceMapper.selectBizDeviceBySn(sn);
        //如果不存在则执行安装
        if (null == device) {
            log.info("设备【{}】尚未安装,执行安装", sn);
            bizDevice.setLastUpdateTime(new Date());
            bizDevice.setTenantId(0L);
            bizDevice.setLineStatus(LineStatus.ON_LINE.getCode());
            bizDevice.setDeviceType(DeviceType.WECHAT.getCode());
            bizDevice.setStatus(EnableStatus.DISABLE.getCode());
            bizDevice.setStockStatus(YesOrNo.YES.getCode());
            if (StringUtils.isBlank(bizDevice.getDoorLockStatus())) {
                bizDevice.setDoorLockStatus(DoorLockStatus.CLOSE.getCode());
            }
            bizDevice.setRenewStatus(RenewStatus.NORMAL.getCode());
            bizDevice.setDueDtime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, "2100-12-29 23:59:59"));
            insertBizDevice(bizDevice);
        } else {
            log.info("设备【{}】已安装,执行更新", sn);
            //如果存在则执行更新
            BizDeviceBO bo = new BizDeviceBO();
            BeanUtils.copyProperties(bizDevice, bo);
            BeanUtils.copyProperties(bo, device);
            device.setLineStatus(LineStatus.ON_LINE.getCode());
            device.setLastUpdateTime(new Date());
            updateBizDevice(device);
        }
        return 1;
    }

    /**
     * 修改设备
     *
     * @param bizDevice 设备
     * @return 结果
     */
    @Override
    public int updateBizDevice(BizDevice bizDevice) {
        bizDevice.setUpdateTime(DateUtils.getNowDate());
        return bizDeviceMapper.updateBizDevice(bizDevice);
    }

    /**
     * 批量删除设备
     *
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteBizDeviceByIds(String ids) {
        String [] arr = Convert.toStrArray(ids);
        for(String id:arr){
            BizDevice bizDevice = selectBizDeviceById(ToolUtils.objTOLong(id));
            if(null == bizDevice){
                continue;
            }
            if(EnableStatus.ENABLE.getCode().equals(bizDevice.getStatus())){
                throw new BaseException("设备【"+bizDevice.getDeviceCode()+"】不是禁用状态,不能删除");
            }
            if(isHaveCargo(bizDevice.getDeviceCode())){
                throw new BaseException("设备【"+bizDevice.getDeviceCode()+"】存在端口,不能删除");
            }
        }
        return bizDeviceMapper.deleteBizDeviceByIds(arr);
    }

    /**
     * 是否存在端口
     * @param sn
     * @return boolean
     */
    private boolean isHaveCargo(String sn){
        BizDeviceCargo query = new BizDeviceCargo();
        query.setDeviceSn(sn);
        List<BizDeviceCargo> cargos = bizDeviceCargoMapper.selectBizDeviceCargoList(query);
        if(!CollectionUtils.isEmpty(cargos)){
            return true;
        }
        return false;
    }
    /**
     * 删除设备信息
     *
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteBizDeviceById(Long id) {
        return bizDeviceMapper.deleteBizDeviceById(id);
    }
}
